package com.innovation.ic.im.end.web.endpoint;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.innovation.ic.b1b.framework.util.StringUtils;
import com.innovation.ic.im.end.base.model.im_erp9.Message;
import com.innovation.ic.im.end.base.pojo.ServiceResult;
import com.innovation.ic.im.end.base.pojo.constant.Constants;
import com.innovation.ic.im.end.base.pojo.constant.RabbitMqExchangeMap;
import com.innovation.ic.im.end.base.pojo.constant.RedisStorage;
import com.innovation.ic.im.end.base.pojo.constant.UserLoginType;
import com.innovation.ic.im.end.base.handler.helper.HandlerHelper;
import com.innovation.ic.im.end.base.handler.im_erp9.WebSocketHandler;
import com.innovation.ic.im.end.base.vo.im_erp9.LoginTypeVo;
import com.innovation.ic.im.end.base.vo.im_erp9.MessageVo;
import com.innovation.ic.im.end.web.config.GetHttpSessionConfigurator;
import com.innovation.ic.im.end.web.thread.SaveMessageThread;
import com.innovation.ic.im.end.base.thread.web.SaveUserLoginLogThread;
import com.innovation.ic.im.end.web.thread.SendSelfMessageThread;
import lombok.Data;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;

@Data
@Component
@ServerEndpoint(value = "/ws/v1/{username}", configurator = GetHttpSessionConfigurator.class)
public class Endpoint extends AbstractEndpoint {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 与客户端的链接会话，需要通过它给客户端发送数据
     */
    public Session session;

    /**
     * 建立连接
     * @param username
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session, EndpointConfig config) {
        Map<String, Object> userProperties = session.getUserProperties();

        // 验证参数
        if (!StringUtils.validateParameter(username)) {
            logger.warn("参数username不能为空");
            return;
        }

        // 获取登录类型
        Integer loginType = getLoginType(userProperties);
        logger.info("当前用户:[{}]登录类型为[{}]", username, loginType);
        LoginTypeVo loginTypeVo = new LoginTypeVo(username, loginType);
        String usernameStr = JSONObject.toJSON(loginTypeVo).toString();

        // 把自己的信息加入到map当中去
        this.session = session;
        onlineMap.put(usernameStr, this);

        // 将onlineMap对象存储到redis中
        WebSocketHandler webSocketHandler = HandlerHelper.getWebSocketHandler();

        // 获取Endpoint类中的onlineMap对象判断用户是否已登录
        Set<String> redisOnlineMap = webSocketHandler.getOnlineMap(RedisStorage.ONLINE_MAP);
        if (redisOnlineMap != null && redisOnlineMap.size() > 0) {
            boolean result = Boolean.FALSE;
            for (String data : redisOnlineMap) {
                if (data.contains(usernameStr)) {
                    result = Boolean.TRUE;
                    break;
                }
            }
            if (!result) {
                // 记录用户登录信息
                JSONObject json = new JSONObject();
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(Constants.LOGGER, JSON.toJSONString(this.getLogger()));
                json.put(usernameStr, jsonObject.toString());
                webSocketHandler.putOnlineMap(RedisStorage.ONLINE_MAP, json);
            }
        } else {
            // 记录用户登录信息
            JSONObject json = new JSONObject();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(Constants.LOGGER, JSON.toJSONString(this.getLogger()));
            json.put(usernameStr, jsonObject.toString());
            webSocketHandler.putOnlineMap(RedisStorage.ONLINE_MAP, json);
        }
        logger.info("session的id为【" + session.getId() + "】，用户名【" + username + "】，当前在线人数:【" + onlineMap.size() + "】");

        // 向最近联系人推送mq消息
        //sendMqMsgToLastContact(username);

        // 进行记录用户登录信息
        String ip = (String) userProperties.get(UserLoginType.IP_ADDR);
        logger.info("当前请求ip为[{}]", ip);
        logger.info("session中的ip为[{}]", session.getUserProperties().get(UserLoginType.IP_ADDR).toString());
        SaveUserLoginLogThread saveUserLoginLogThread = new SaveUserLoginLogThread(username, UserLoginType.POINT_TO_POINT, ip);
        threadPoolManager.execute(saveUserLoginLogThread);
    }

    /**
     * 报错
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose(Session session, CloseReason reason) {
        CloseReason.CloseCode closeCode = reason.getCloseCode();
        logger.info("Closing session => '{}' - '{}'", session, reason);
        int code = closeCode.getCode();

        Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
        List<String> list = requestParameterMap.get(Constants.USER_NAME);
        if(list != null && list.size() > 0){
            // 当前退出登录的用户名
            String logoutUserName = list.get(0);

            Iterator iterator = onlineMap.keySet().iterator();
            while (iterator.hasNext()) {
                String username = (String) iterator.next();
                JSONObject json = (JSONObject) JSONObject.parse(username);

                String onlineMapUserName = json.getString(Constants.USER_NAME);
                if (logoutUserName.equals(onlineMapUserName)) {
                    if(code == Constants.CLOSE_BROWSER_WS_CODE){
                        // 浏览器关闭时，将当前用户所有的聊天页面状态设置为关闭

                        ServiceResult<Boolean> serviceResult = chatPairService.closeAccountChatPageStatus(onlineMapUserName);
                        if(serviceResult.getResult()){
                            logger.info("将当前用户[{}]所有的聊天页面状态设置为关闭成功", username);
                        }
                    }

                    // 将onlineMap对象从redis中删除,获取当前在线用户数量
                    Long onlineAccountCount = delOnlineMapFromRedis(username);
                    iterator.remove();
                    logger.info("用户【" + username + "】关闭了连接，当前在线人数:【" + onlineAccountCount + "】");
                }
            }
        }
    }

    /**
     * 将onlineMap对象从redis中删除
     * @param username  用户名
     * @return 返回当前在线用户总数
     */
    private Long delOnlineMapFromRedis(String username) {
        WebSocketHandler webSocketHandler = HandlerHelper.getWebSocketHandler();
        // 根据键值从redis中取onlineMap数据
        Set<String> redisData = webSocketHandler.getOnlineMap(RedisStorage.ONLINE_MAP);
        if (redisData != null && !redisData.isEmpty()) {
            boolean delFlag = Boolean.FALSE;
            for (String data : redisData) {
                if (data.contains(username)) {
                    Long result = webSocketHandler.delOnlineMapValue(RedisStorage.ONLINE_MAP, data);
                    if (result.intValue() == 1) {
                        logger.info("用户:[{}]的登录信息已从redis中删除", username);
                        delFlag = Boolean.TRUE;
                        break;
                    }
                }
            }
            if (!delFlag) {
                logger.info("用户:[{}]的登录信息未从redis中查到,无法删除", username);
            }
        } else {
            logger.info("redis中不存在用户登录信息,不进行删除操作");
        }
        // 获取当前在线用户数量
        return webSocketHandler.getRedisKeySize(RedisStorage.ONLINE_MAP);
    }

    /**
     * 收到客户端A的消息，将其发送给客户端B。如果客户端B还没有上线，则暂时将消息存储在数据库中
     * @param messageString 消息
     * @param session       会话
     */
    @OnMessage
    public void onMessage(String messageString, Session session) {
        // 验证参数
        if (!StringUtils.validateParameter(messageString)) {
            logger.warn("参数messageString不能为空");
            return;
        }
        MessageVo messageVo = JSON.parseObject(messageString, MessageVo.class);
        // type为-1时表示心跳，前端每隔5秒发送一次心跳，以免1分钟后websocket自动断开连接
        if (messageVo.getType() == -1) {
            return;
        }
        if (!StringUtils.validateParameter(messageVo.getContent())
                || !StringUtils.validateParameter(messageVo.getFromUserAccount())
                || !StringUtils.validateParameter(messageVo.getToUserAccount())
                || null == messageVo.getType()) {
            logger.warn("参数content, fromUserAccount, toUserAccount和type不能为空");
            return;
        }
        logger.info("来自用户的消息【" + messageString + "】，客户端的session的id是【" + session.getId() + "】");

        try {
            Message message = modelHandler.toMessage(messageVo);

            // 获取登录类型
            List<Integer> loginTypeList = getLoginTypeList();

            // 获取账号类别
            Integer integration = getIntegration(messageVo.getToUserAccount());

            // 对自己和自己聊天的情况做特殊处理
            if(messageVo.getFromUserAccount().equals(messageVo.getToUserAccount())){
                SendSelfMessageThread sendSelfMessageThread = new SendSelfMessageThread(message, onlineMap, messageVo,
                        rabbitMqParamConfig.getExchange().get(RabbitMqExchangeMap.CURRENT_EXCHANGE), loginTypeList, integration);
                threadPoolManager.execute(sendSelfMessageThread);
            }else{
                // 记录消息
                SaveMessageThread saveMessageThread = new SaveMessageThread(message, onlineMap, messageVo,
                        rabbitMqParamConfig.getExchange().get(RabbitMqExchangeMap.CURRENT_EXCHANGE), loginTypeList,
                        rabbitMqParamConfig.getExchange().get(RabbitMqExchangeMap.READ_STATE_UPDATE_MSG_EXCHANGE), threadPoolManager, integration,
                        rabbitMqParamConfig.getExchange().get(RabbitMqExchangeMap.SC_READ_STATE_UPDATE_MSG_EXCHANGE));
                threadPoolManager.execute(saveMessageThread);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}